package com.sudo.service.admin.service.impl;

import com.github.pagehelper.PageHelper;
import com.sudo.common.component.RedisKeys;
import com.sudo.common.constant.UserConstant;
import com.sudo.common.enums.SysStatus;
import com.sudo.common.enums.SysUserSource;
import com.sudo.common.enums.SysYesNo;
import com.sudo.common.utils.LocalDateTimeUtil;
import com.sudo.common.utils.MD5Util;
import com.sudo.common.utils.PagedGridResult;
import com.sudo.dao.admin.entity.SysAutoRole;
import com.sudo.dao.admin.entity.SysUser;
import com.sudo.dao.admin.entity.SysUserRole;
import com.sudo.dao.admin.mapper.SysAutoRoleMapper;
import com.sudo.dao.admin.mapper.SysUserMapper;
import com.sudo.dao.admin.mapper.SysUserMapperCustom;
import com.sudo.dao.admin.mapper.SysUserRoleMapper;
import com.sudo.dao.admin.model.bo.SimpleUserBO;
import com.sudo.dao.admin.model.bo.SysUserBasicInfoBO;
import com.sudo.dao.admin.model.bo.sysconfig.SysUserRegistDTO;
import com.sudo.dao.admin.model.vo.SysSimpleUserVO;
import com.sudo.dao.admin.model.vo.SysUserMainVO;
import com.sudo.dao.admin.model.vo.SysUserOnlineVO;
import com.sudo.dao.admin.model.vo.SysUserReVO;
import com.sudo.service.admin.service.AdminBaseService;
import com.sudo.service.admin.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Slf4j
@Service
public class SysUserServiceImpl extends AdminBaseService implements SysUserService {

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private SysUserRoleMapper sysUserRoleMapper;

    @Resource
    private SysUserMapperCustom sysUserMapperCustom;

    @Resource
    private SysAutoRoleMapper sysAutoRoleMapper;

    /**
     * 通过用户名获取用户信息
     * @param username 用户名
     * @return sysUser
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public SysUser getSysUserWithoutPwdByUsername(String username) {

        Example example = new Example(SysUser.class);
        example.excludeProperties("password");
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username",username);
        return sysUserMapper.selectOneByExample(example);
    }

    /**
     * 通过用户名获取用户信息
     * @param mail 用户名
     * @return sysUser
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public SysUser getSysUserWithoutPwdByMail(String mail) {

        Example example = new Example(SysUser.class);
        example.excludeProperties("password");
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("mail",mail);
        return sysUserMapper.selectOneByExample(example);
    }

    /**
     * 通过用户名获取用户信息
     * @param username 用户名
     * @return sysUser
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public SysUser getSysUserByUsername(String username) {

        Example example = new Example(SysUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username",username);
        return sysUserMapper.selectOneByExample(example);
    }

    /**
     * 通过邮件获取用户信息
     * @param mail 邮件
     * @return SysUser
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public SysUser getSysUserByMail(String mail) {
        Example example = new Example(SysUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("mail",mail);
        return sysUserMapper.selectOneByExample(example);
    }


    /**
     * 分页获取用户信息，查询条件 = 用户名，昵称，邮箱
     * @param page 当前页
     * @param pageSize 每页行数
     * @param usernameOrNick 参数（用户名，昵称，邮箱）
     * @return pageResult
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public PagedGridResult queryAllSysUserMainInfoByPage(Integer page , Integer pageSize , String usernameOrNick) {
        PageHelper.startPage(page, pageSize);
        List<SysUserMainVO> sysUserList = sysUserMapperCustom.getAllSysUserMainInfo(usernameOrNick);

        return setterPagedGrid(sysUserList ,page);
    }

    /**
     * 通过用户名获取用户信息和其对应的角色
     * @param username 用户名
     * @return sysUserReVO
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public SysUserReVO getSysUserAndRoleByUsername(String username) {
        return sysUserMapperCustom.getSysUserAndRoleByUsername(username);
    }

    /**
     * 新增用户，包含角色code
     * @param simpleUserBO 参数（用户信息，角色code）
     * @param sessionUser 当前session用户
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int addUser(SimpleUserBO simpleUserBO , String sessionUser) {
        LocalDateTime now = LocalDateTime.now();
        //1.添加用户信息
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(simpleUserBO, sysUser,"roleCode");
        sysUser.setCreateBy(sessionUser);
        String nowDateTimeStr = LocalDateTimeUtil.convertLocateDateTime2Str(now, LocalDateTimeUtil.yyyy_MM_dd_HH_mm_ss);
        sysUser.setCreateTime(nowDateTimeStr);
        sysUser.setStatus(SysStatus.ON.name());
        sysUser.setSource(SysUserSource.MANUAL.name());
        String md5Pwd = MD5Util.getMD5Str(sysUser.getPassword());
        sysUser.setPassword(md5Pwd);

        //2.添加角色用户的关联关系
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setRoleCode(simpleUserBO.getRoleCode());
        sysUserRole.setUsername(sysUser.getUsername());
        sysUserRoleMapper.insertSelective(sysUserRole);

        //3.添加自动化角色（sys_auto_role)
        SysAutoRole sysAutoRole = new SysAutoRole();
        sysAutoRole.setSetupRole(simpleUserBO.getRoleCode());
        sysAutoRole.setExpiryRole(simpleUserBO.getRoleCode());
        sysAutoRole.setUsername(sysUser.getUsername());
        sysAutoRole.setSource(SysUserSource.MANUAL.name());
        sysAutoRole.setExpirationTime(now.withSecond(0));
        sysAutoRole.setIsExpired(SysYesNo.NO.name());
        sysAutoRole.setStatus(SysStatus.OFF.name());
        sysAutoRoleMapper.insertSelective(sysAutoRole);

        int affectCount = sysUserMapper.insertSelective(sysUser);

        //====== redis ======
        if (affectCount > 0) {
            // redis_role_user (添加用户)
            setRedisRoleUserToRedis(simpleUserBO.getRoleCode(), simpleUserBO.getUsername());
        }
        return affectCount;
    }

    /**
     * 切换用户角色或状态
     * @param username 用户名
     * @param roleCode 角色代码
     * @param status 用户状态
     * @return 数量
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int updateSysUserRoleStatus(String username, String roleCode, String status) {
        int affectCount = 0;
        //更新用户-角色关联关系
        Example example = new Example(SysUserRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username", username);

        //查询原始数据
        SysUserReVO sysUserReVO = getSysUserAndRoleByUsername(username);

        boolean changeRole = !sysUserReVO.getRoleCode().equals(roleCode);
        boolean changeStatus = !sysUserReVO.getStatus().equals(status);

        //判断角色有没有变化,若有变化则修改数据库
        if (changeRole) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setRoleCode(roleCode);
            affectCount = sysUserRoleMapper.updateByExampleSelective(sysUserRole, example);
        }

        //判断状态有没有变化，若有变化则修改数据库
        if (changeStatus) {
            Example example1 = new Example(SysUser.class);
            Example.Criteria criteria1 = example1.createCriteria();
            criteria1.andEqualTo("username", username);
            SysUser sysUser = new SysUser();
            sysUser.setStatus(status);
            affectCount = sysUserMapper.updateByExampleSelective(sysUser, example1);
        }

        //====== redis ======
        //1.角色不变，状态变化
        if (!changeRole && changeStatus) {
            //on
            if (SysStatus.ON.name().equals(status)) {
                setRedisRoleUserToRedis(roleCode,username);
            }else{
            //off
                delRedisRoleUserFromRedis(roleCode,username);
            }
        } else if (changeRole && !changeStatus) {
        //2.角色变化，状态不变
            if (SysStatus.ON.name().equals(status)) {
                updateRedisRoleForUser(username, sysUserReVO.getRoleCode(), roleCode);
            }
        } else if (changeRole && changeStatus) {
        //3.角色变化，状态变化
            //on
            if (SysStatus.ON.name().equals(status)) {
                setRedisRoleUserToRedis(roleCode,username);
            }else{
                //off
                delRedisRoleUserFromRedis(sysUserReVO.getRoleCode(),username);
            }
        }
        return affectCount;
    }

    /**
     * 删除用户信息
     * @param username 用户名
     * @return 数量
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int deleteSysUserByUsername(String username) {
        Example example = new Example(SysUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username", username);

        //查询原始数据
        SysUserReVO sysUserReVO = getSysUserAndRoleByUsername(username);

        //删除用户-角色关联关系
        Example example1 = new Example(SysUserRole.class);
        Example.Criteria criteria1 = example1.createCriteria();
        criteria1.andEqualTo("username", username);
        sysUserRoleMapper.deleteByExample(example1);

        //删除角色自动化
        Example example2 = new Example(SysAutoRole.class);
        Example.Criteria criteria2 = example2.createCriteria();
        criteria2.andEqualTo("username",username);
        sysAutoRoleMapper.deleteByExample(example2);

        int affectCount = sysUserMapper.deleteByExample(example);

        //====== redis ======
        if (affectCount > 0) {
            //删除 redis_role_user (可用角色-可用用户)
            if (SysStatus.ON.name().equals(sysUserReVO.getStatus())) {
                delRedisRoleUserFromRedis(sysUserReVO.getRoleCode(),username);
            }
            //删除 redis_user_token (用户登录信息)
            delRedisUserTokenFromRedis(username);
        }
        return affectCount;
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    @Override
    public PagedGridResult getOnlineUserByPage(Integer page, Integer pageSize) {
        Set<String> keys = stringRedisUtil.keys(redisKeys.redisUserToken("*"));
        List<String> list = new ArrayList<>();
        for (String key : keys) {
            String onlineUser = key.replace(RedisKeys.REDIS_USER_TOKEN + ":", "");
            list.add(onlineUser);
        }
        PageHelper.startPage(page, pageSize);
        List<SysUserOnlineVO> sysUserOnlineVOList = sysUserMapperCustom.getOnlineUser(list);

        return setterPagedGrid(sysUserOnlineVOList,page);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int updateMyUserInfo(SysUserBasicInfoBO basicInfoBO, String sessionUser) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(basicInfoBO, sysUser, "username");
        sysUser.setUpdateBy(sessionUser);
        sysUser.setUpdateTime(LocalDateTime.now().toString());
        Example example = new Example(SysUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username", basicInfoBO.getUsername());
        return sysUserMapper.updateByExampleSelective(sysUser, example);
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    @Override
    public SysSimpleUserVO getMySimpleUserInfo(String username) {
        if (StringUtils.isBlank(username)) {
            return null;
        }
        return sysUserMapperCustom.getMySimpleUserInfo(username);
    }

    @Override
    public int updateMyPassword(String sessionUser, String newPassword) {
        String newPasswordMd5 = MD5Util.getMD5Str(newPassword);
        Example example = new Example(SysUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username", sessionUser);

        SysUser sysUser = new SysUser();
        sysUser.setPassword(newPasswordMd5);
        sysUser.setUpdateBy(sessionUser);
        sysUser.setUpdateTime(LocalDateTimeUtil.getStandardDateTimeStr());

        return sysUserMapper.updateByExampleSelective(sysUser,example);
    }


    // SCC 模块注册，每个模块注册属于独立
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int userRegister(String email, String username, String password,
                            SysUserSource source, SysUserRegistDTO sysUserRegistDTO) {
        SysUser sysUser = new SysUser();
        sysUser.setMail(email);
        sysUser.setUsername(username);
        LocalDateTime now = LocalDateTime.now();
        String nowTime = LocalDateTimeUtil.convertLocateDateTime2Str(now,LocalDateTimeUtil.yyyy_MM_dd_HH_mm_ss);
        String md5Str = MD5Util.getMD5Str(password);
        sysUser.setPassword(md5Str);
        sysUser.setSource(source.name());
        sysUser.setCreateBy(UserConstant.SUPER_NAME);
        sysUser.setStatus(SysStatus.ON.name());
        sysUser.setCreateTime(nowTime);
        //1.添加角色用户的关联关系
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setRoleCode(sysUserRegistDTO.getRegist_role());
        sysUserRole.setUsername(username);
        sysUserRoleMapper.insertSelective(sysUserRole);

        // 2.添加用户注册表
        SysAutoRole sysAutoRole = new SysAutoRole();
        sysAutoRole.setSetupRole(sysUserRegistDTO.getRegist_role());
        sysAutoRole.setExpiryRole(sysUserRegistDTO.getExpiry_role());
        sysAutoRole.setIsExpired(SysYesNo.NO.name());
        sysAutoRole.setUsername(username);
        sysAutoRole.setSource(source.name());
        sysAutoRole.setStatus(SysStatus.ON.name());
        Integer defExpiryTime = Integer.parseInt(sysUserRegistDTO.getDef_expiry_time());
        LocalDateTime expirationTime = now.withSecond(0).plusMinutes(defExpiryTime);
        sysAutoRole.setExpirationTime(expirationTime);
        sysAutoRoleMapper.insertSelective(sysAutoRole);

        // 3.添加用户
        int affectCount = sysUserMapper.insertSelective(sysUser);
        //====== redis ======
        if (affectCount > 0) {
            // redis_role_user (添加用户)
            setRedisRoleUserToRedis(sysUserRegistDTO.getRegist_role(), username);
        }
        return affectCount;
    }

    @Override
    public List<SysUser> getAllUsername() {
        Example example = new Example(SysUser.class);
        example.selectProperties("username");
        return sysUserMapper.selectByExample(example);
    }
}
